package art.client.widgets;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import art.client.services.UserService;
import art.client.services.UserServiceAsync;
import art.shared.entities.ArtShared;
import art.shared.entities.GenreShared;
import art.shared.entities.LoginInfo;
import art.shared.entities.UserLevelShared;
import art.shared.entities.UserShared;

import com.google.gwt.core.shared.GWT;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;

public class ArtTable implements IsWidget {

	private CellTable<ArtShared> cellTable = null;
	private List<ArtShared> arts = null;
	private TextColumn<ArtShared> artCreatorColumn;
	private TextColumn<ArtShared> artTitleColumn;
	private Column<ArtShared, Date> artUploadedOnColumn;
	private List<UserShared> users = null;
	private ListDataProvider<ArtShared> dataProvider;
	private Column<ArtShared, Number> artAvgRatingColumn;
	private List<ArtShared> filteredArts = null;
	private List<GenreShared> genres = null;

	public ArtTable(List<ArtShared> arts, LoginInfo loginInfo,
			final boolean allowDelete, List<GenreShared> genres) {
		super();
		this.genres = genres;
		this.arts = arts;
		initWidget(loginInfo, allowDelete);
	}

	private void initWidget(final LoginInfo loginInfo, final boolean allowDelete) {
		cellTable = new CellTable<ArtShared>();
		UserServiceAsync userService = GWT.create(UserService.class);
		userService.getUsers(new AsyncCallback<List<UserShared>>() {

			@Override
			public void onSuccess(final List<UserShared> users) {
				addColumns(users, loginInfo, allowDelete);
			}

			@Override
			public void onFailure(Throwable arg0) {
			}
		});
		cellTable.setRowCount(arts.size(), true);
		dataProvider = new ListDataProvider<ArtShared>();
		dataProvider.setList(arts);
		dataProvider.addDataDisplay(cellTable);
	}

	@Override
	public Widget asWidget() {
		return cellTable;
	}

	private void addColumns(final List<UserShared> users,
			final LoginInfo loginInfo, boolean allowDelete) {
		TableColumnFactory factory = TableColumnFactory.getFactory();
		this.users = users;
		artTitleColumn = factory.getArtTitleColumn();
		artCreatorColumn = factory.getArtCreatorColumn(users);
		TextColumn<ArtShared> artGenreColumn = factory
				.getArtGenreColumn(genres);
		artUploadedOnColumn = factory.getArtUploadedOnColumn();
		artAvgRatingColumn = factory.getArtAvgRatingColumn();
		Column<ArtShared, String> artDownloadColumn = factory
				.getArtDownloadColumn(users);
		cellTable.addColumn(artTitleColumn, "Title");
		cellTable.addColumn(artCreatorColumn, "Creator");
		cellTable.addColumn(artGenreColumn, "Genre");
		cellTable.addColumn(artUploadedOnColumn, "Uploaded On");
		cellTable.addColumn(artAvgRatingColumn, "Average rating");
		cellTable.addColumn(artDownloadColumn);
		cellTable.addColumn(factory.getArtViewReviewsColumn(users));
		if (loginInfo != null) {
			if (!loginInfo.getUserLevel().equals(UserLevelShared.VISITOR)) {
				cellTable.addColumn(factory.getArtAddReviewColumn(users,
						loginInfo));
			}
		}
		if (allowDelete) {
			cellTable.addColumn(factory.getArtDeleteColumn(this));
		}
	}
	
	public ListDataProvider<ArtShared> getDataProvider() {
		return dataProvider;
	}

	public void updateData(List<ArtShared> arts) {
		this.arts = arts;
		dataProvider.setList(arts);
		ListHandler<ArtShared> columnSortHandler = new ListHandler<ArtShared>(
				dataProvider.getList());
		columnSortHandler.setComparator(artCreatorColumn,
				new Comparator<ArtShared>() {

					@Override
					public int compare(ArtShared o1, ArtShared o2) {
						String creator1 = null;
						String creator2 = null;
						boolean found1 = false;
						boolean found2 = false;
						for (UserShared user : users) {
							if (found1 && found2) {
								break;
							}
							if (user.getId() == o1.getCreatorId()) {
								creator1 = user.getName();
								found1 = true;
							}
							if (user.getId() == o2.getCreatorId()) {
								creator2 = user.getName();
								found1 = true;
							}
							if (creator1 == null) {
								return -1;
							}
							if (creator2 == null) {
								return 1;
							}
							if (creator1.equals(creator2)) {
								return 0;
							}
							return creator1.compareTo(creator2);
						}
						return 0;
					}
				});
		columnSortHandler.setComparator(artTitleColumn,
				new Comparator<ArtShared>() {

					@Override
					public int compare(ArtShared o1, ArtShared o2) {
						String title1 = o1.getTitle();
						String title2 = o2.getTitle();
						if (title1 == null) {
							return -1;
						}
						if (title2 == null) {
							return 1;
						}
						if (title1.equals(title2)) {
							return 0;
						}
						return title1.compareTo(title2);
					}
				});
		columnSortHandler.setComparator(artUploadedOnColumn,
				new Comparator<ArtShared>() {

					@Override
					public int compare(ArtShared o1, ArtShared o2) {
						Date uploadedOn1 = o1.getUploadedOn();
						Date uploadedOn2 = o2.getUploadedOn();
						if (uploadedOn1 == null) {
							return -1;
						}
						if (uploadedOn2 == null) {
							return 1;
						}
						if (uploadedOn1.before(uploadedOn2)) {
							return -1;
						} else if (uploadedOn1.after(uploadedOn2)) {
							return 1;
						} else {
							return 0;
						}
					}
				});
		columnSortHandler.setComparator(artAvgRatingColumn,
				new Comparator<ArtShared>() {

					@Override
					public int compare(ArtShared o1, ArtShared o2) {
						return new Double(o1.getAvgRating() - o2.getAvgRating())
								.intValue();
					}
				});
		cellTable.addColumnSortHandler(columnSortHandler);
		cellTable.getColumnSortList().push(artTitleColumn);
	}

	public void applyTitleFilter(String text) {
		filteredArts = new ArrayList<ArtShared>();
		for (ArtShared art : arts) {
			if (art.getTitle().contains(text)) {
				filteredArts.add(art);
			}
		}
		dataProvider.setList(filteredArts);
	}

	public void applyCreatorFilter(String text) {
		filteredArts = new ArrayList<ArtShared>();
		if (text.isEmpty()) {
			filteredArts = arts;
		} else {
			for (ArtShared art : arts) {
				for (UserShared user : users) {
					if (user.getId() == art.getCreatorId()) {
						if (user.getName().contains(text)) {
							filteredArts.add(art);
						}
						break;
					}
				}
			}
		}
		dataProvider.setList(filteredArts);
	}

	public void applyGenreFilter(String text) {
		filteredArts = new ArrayList<ArtShared>();
		if (genres != null) {
			boolean found = false;
			List<GenreShared> tmpGenre = new ArrayList<GenreShared>();
			List<Long> tmpIds = new ArrayList<Long>();
			for (GenreShared genre : genres) {
				if (genre.getName().contains(text)) {
					tmpGenre.add(genre);
					tmpIds.add(genre.getId());
					found = true;
				}
			}
			while(found) {
				found = false;
				List<Long> tempIds = tmpIds;
				tmpIds = new ArrayList<Long>();
				for (GenreShared genre: genres) {
					for (Long tmp :tempIds) {
						if (genre.getParentId() != null && genre.getParentId().longValue() == tmp.longValue()) {
							tmpGenre.add(genre);
							tmpIds.add(genre.getId());
							found = true;
							break;
						}
					}
				}
			}
			for (ArtShared art : arts) {
				for (GenreShared g :tmpGenre) {
					if (art.getGenre().getId() == g.getId()) {
						filteredArts.add(art);
						break;
					}
				}
			}
		}
		dataProvider.setList(filteredArts);
	}
}
